part of '../store.dart';

Future<void> _handleMigrationFromFirstVersionToSecondOne() async {
  final futureResults = await Future.wait([
    Hive.openBox('ru'),
    Hive.openBox('settings'),
    Hive.openBox('user'),
    Hive.openBox('analytics'),
    Hive.openBox('user_store'),
  ]);

  var i = 0;

  final ruBox = futureResults[i++];
  final settingsBox = futureResults[i++];
  final userBox = futureResults[i++];
  final analyticsBox = futureResults[i++];
  final storeBox = futureResults[i++];

  final storeBoxContent = <String, dynamic>{};

  // ru box content migration

  final ruBoxContent = ruBox.toMap();
  final ruBoxVersion = ruBoxContent['version'] as int?;

  if (ruBoxVersion != null) {
    var migratedRuBoxContent = ruBoxContent.build();
    var migratedRuBoxVersion = ruBoxVersion;

    if (migratedRuBoxVersion == 1) {
      migratedRuBoxContent = _migrateRuBoxContentFromFirstVersionToSecondOne(
        ruBoxContent: migratedRuBoxContent,
      );

      migratedRuBoxVersion = 2;
    }

    if (migratedRuBoxVersion == 2) {
      migratedRuBoxVersion = 3;
    }

    if (migratedRuBoxVersion == 3) {
      migratedRuBoxContent = _migrateRuBoxContentFromThirdVersionToFourthOne(
        ruBoxContent: migratedRuBoxContent,
      );

      migratedRuBoxVersion = 4;
    }

    storeBoxContent['learning_content.lexical_items'] = migratedRuBoxContent['lexical_items'];
    storeBoxContent['learning_content.collection_list_items'] =
        migratedRuBoxContent['collection_list_items'];
    storeBoxContent['learning_content.merged_asset_learning_content_version'] = 1;
  }

  // settings box content migration

  final settingsBoxContent = settingsBox.toMap();
  final settingsBoxVersion = settingsBoxContent['version'] as int?;

  if (settingsBoxVersion != null) {
    var migratedSettingsBoxContent = settingsBoxContent.build();
    var migratedSettingsBoxVersion = settingsBoxVersion;

    if (migratedSettingsBoxVersion == 1) {
      migratedSettingsBoxContent = _migrateSettingsBoxContentFromFirstVersionToSecondOne(
        settingsBoxContent: migratedSettingsBoxContent,
      );

      migratedSettingsBoxVersion = 2;
    }

    storeBoxContent['settings.appearance_settings'] =
        migratedSettingsBoxContent['appearance_settings'];
    storeBoxContent['settings.image_settings'] = migratedSettingsBoxContent['image_settings'];
    storeBoxContent['settings.interface_language_code'] =
        migratedSettingsBoxContent['interface_language_code'];
    storeBoxContent['settings.pronunciation_settings'] =
        migratedSettingsBoxContent['pronunciation_settings'];
    storeBoxContent['settings.learning_settings'] = migratedSettingsBoxContent['learning_settings'];
  }

  // user box content migration

  final userBoxContent = userBox.toMap();
  final userBoxVersion = userBoxContent['version'] as int?;

  if (userBoxVersion != null) {
    var migratedUserBoxContent = userBoxContent.build();
    var migratedUserBoxVersion = userBoxVersion;

    if (migratedUserBoxVersion == 1) {
      migratedUserBoxContent = _migrateUserBoxContentFromFirstVersionToSecondOne(
        userBoxContent: migratedUserBoxContent,
      );

      migratedUserBoxVersion = 2;
    }

    storeBoxContent['user.learning_info'] = migratedUserBoxContent['learning_info'];
    storeBoxContent['user.app_review_request_times'] =
        migratedUserBoxContent['app_review_request_times'];
    storeBoxContent['user.intro_finished'] = migratedUserBoxContent['intro_finished'];
    storeBoxContent['user.initial_app_version_code'] =
        migratedUserBoxContent['initial_app_version_code'];
    storeBoxContent['user.access_credentials'] = migratedUserBoxContent['access_credentials'];
    storeBoxContent['user.user'] = migratedUserBoxContent['user'];
    storeBoxContent['user.device_id'] = migratedUserBoxContent['device_id'];
  }

  // analytics box content migration

  final analyticsBoxContent = analyticsBox.toMap();

  storeBoxContent['analytics.first_launch_logged'] = analyticsBoxContent['first_launch_logged'];
  storeBoxContent['analytics.intro_start_logged'] = analyticsBoxContent['intro_start_logged'];
  storeBoxContent['analytics.intro_welcome_pass_logged'] =
      analyticsBoxContent['intro_welcome_pass_logged'];
  storeBoxContent['analytics.intro_finish_logged'] = analyticsBoxContent['intro_finish_logged'];

//

  storeBoxContent['version'] = 2;
  await storeBox.putAll(storeBoxContent);
  await storeBox.close();
}

BuiltMap _migrateRuBoxContentFromFirstVersionToSecondOne({
  required BuiltMap ruBoxContent,
}) {
  final updatedRuBoxContent = ruBoxContent.rebuild((ruBoxContent) {
    ruBoxContent['collection_list_items'] = ruBoxContent.remove('collections');
    ruBoxContent['lexical_items_progress'] = ruBoxContent['lexical_items_progress'] ?? {};
    ruBoxContent['added_to_brain_boost_unknown_lexical_item_times_ms'] =
        ruBoxContent['added_to_brain_boost_unknown_lexical_item_times_ms'] ?? [];

    final collectionSettingsJson =
        Map.castFrom<dynamic, dynamic, String, dynamic>(ruBoxContent['collections_settings'] ?? {});

    final collectionListItemMaps =
        List.castFrom<dynamic, Map>(ruBoxContent['collection_list_items']);

    const defaultCollectionSettingsJson = {
      'selected': false,
      'high_priority': false,
      'sorting': 'alphabetically',
    };

    final collectionIds = <String>{};

    for (final collectionListItemMap in collectionListItemMaps) {
      final collectionListItemJson =
          Map.castFrom<dynamic, dynamic, String, dynamic>(collectionListItemMap);

      if (collectionListItemJson['type'] == 'default_collection' ||
          collectionListItemJson['type'] == 'user_collection') {
        final collectionJson = collectionListItemJson;

        collectionIds.add(collectionJson['id']);
        collectionSettingsJson[collectionJson['id']] =
            collectionSettingsJson[collectionJson['id']] ?? defaultCollectionSettingsJson;
      } else if (collectionListItemJson['type'] == 'default_collection_group' ||
          collectionListItemJson['type'] == 'user_collection_group') {
        final collectionGroupJson = collectionListItemJson;

        final collectionMaps = List.castFrom<dynamic, Map>(collectionGroupJson['collections']);

        for (final collectionMap in collectionMaps) {
          final collectionJson = Map.castFrom<dynamic, dynamic, String, dynamic>(collectionMap);

          collectionIds.add(collectionJson['id']);
          collectionSettingsJson[collectionJson['id']] =
              collectionSettingsJson[collectionJson['id']] ?? defaultCollectionSettingsJson;
        }
      }
    }

    collectionSettingsJson.removeWhere((collectionId, _) {
      return !collectionIds.contains(collectionId);
    });

    ruBoxContent['collections_settings'] = collectionSettingsJson;

    final brainBoostListEntryMaps =
        List.castFrom<dynamic, Map>(ruBoxContent['brain_boost_list'] ?? []);
    var brainBoostListEntryJsons = brainBoostListEntryMaps.map((brainBoostListEntryMap) {
      final brainBoostListEntryJson =
          Map.castFrom<dynamic, dynamic, String, dynamic>(brainBoostListEntryMap);
      return brainBoostListEntryJson;
    }).toList();

    final brainBoostListIds = brainBoostListEntryJsons.map((brainBoostListEntryJson) {
      return brainBoostListEntryJson['lexical_item_id'] as String;
    }).toSet();

    brainBoostListEntryJsons = brainBoostListIds.map((lexicalItemId) {
      return brainBoostListEntryJsons.firstWhere((boostListEntryJson) {
        return boostListEntryJson['lexical_item_id'] == lexicalItemId;
      });
    }).toList();

    ruBoxContent['brain_boost_list'] = brainBoostListEntryJsons;

    final learningQueueEntryMaps =
        List.castFrom<dynamic, Map>(ruBoxContent['learning_queue'] ?? []);
    final learningQueueEntryJsons = learningQueueEntryMaps.map((learningQueueEntryMap) {
      final learningQueueEntryJson =
          Map.castFrom<dynamic, dynamic, String, dynamic>(learningQueueEntryMap);
      return learningQueueEntryJson;
    }).toList();

    learningQueueEntryJsons.removeWhere((learningQueueEntryJson) {
      return brainBoostListIds.contains(learningQueueEntryJson['lexical_item_id']);
    });

    ruBoxContent['learning_queue'] = learningQueueEntryJsons;
  });

  return updatedRuBoxContent;
}

BuiltMap _migrateRuBoxContentFromThirdVersionToFourthOne({
  required BuiltMap ruBoxContent,
}) {
  final updatedRuBoxContent = ruBoxContent.rebuild((ruBoxContent) {
    //
    // lexical item migration
    //
    final lexicalItemMaps = List.castFrom<dynamic, Map>(ruBoxContent['lexical_items']);
    final lexicalItemProgressJson =
        Map.castFrom<dynamic, dynamic, String, dynamic>(ruBoxContent['lexical_items_progress']);

    final brainBoostListItemMaps = List.castFrom<dynamic, Map>(ruBoxContent['brain_boost_list']);

    final brainBoostListItemJsons = brainBoostListItemMaps.map((brainBoostListItemMap) {
      final brainBoostListItemJson =
          Map.castFrom<dynamic, dynamic, String, dynamic>(brainBoostListItemMap);
      return brainBoostListItemJson;
    }).toList();

    final learningQueueItemMaps = List.castFrom<dynamic, Map>(ruBoxContent['learning_queue']);

    final learningQueueItemJsons = learningQueueItemMaps.map((learningQueueItemMap) {
      final learningQueueItemJson =
          Map.castFrom<dynamic, dynamic, String, dynamic>(learningQueueItemMap);
      return learningQueueItemJson;
    }).toList();

    final lexicalItemJsons = lexicalItemMaps.map((map) {
      final lexicalItemJson = Map.castFrom<dynamic, dynamic, String, dynamic>(map);

      // migrate type
      if (lexicalItemJson['type'] == 'user_word') {
        lexicalItemJson['type'] = 'custom_lexical_item';
      } else if (lexicalItemJson['type'] == 'word') {
        switch (lexicalItemJson['part_of_speech']) {
          case 'adjective':
            lexicalItemJson['type'] = 'adjective';
            lexicalItemJson.remove('part_of_speech');
          case 'adverb':
            lexicalItemJson['type'] = 'adverb';
            lexicalItemJson.remove('part_of_speech');
          case 'conjunction':
            lexicalItemJson['type'] = 'conjunction';
            lexicalItemJson.remove('part_of_speech');
          case 'noun':
            lexicalItemJson['type'] = 'noun';
            lexicalItemJson.remove('part_of_speech');
          case 'numeral':
            lexicalItemJson['type'] = 'numeral';
            lexicalItemJson.remove('part_of_speech');
          case 'preposition':
            lexicalItemJson['type'] = 'preposition';
            lexicalItemJson.remove('part_of_speech');
          case 'pronoun':
            lexicalItemJson['type'] = 'pronoun';
            lexicalItemJson.remove('part_of_speech');
          case 'verb':
            lexicalItemJson['type'] = 'verb';
            lexicalItemJson.remove('part_of_speech');
          default:
            throw UnimplementedError();
        }
      }

      // migrate progress
      final lexicalItemId = lexicalItemJson['id'];
      final lexicalItemProgressMap = lexicalItemProgressJson[lexicalItemId];

      Map<String, dynamic>? lexicalItemLearningQueueItemJson;
      for (final learningQueueItemJson in learningQueueItemJsons) {
        if (learningQueueItemJson['lexical_item_id'] == lexicalItemId) {
          lexicalItemLearningQueueItemJson = learningQueueItemJson;
          break;
        }
      }

      Map<String, dynamic>? lexicalItemBrainBoostListItemJson;
      for (final brainBoostListItemJson in brainBoostListItemJsons) {
        if (brainBoostListItemJson['lexical_item_id'] == lexicalItemId) {
          lexicalItemBrainBoostListItemJson = brainBoostListItemJson;
          break;
        }
      }

      if (lexicalItemProgressMap == null) {
        if (lexicalItemLearningQueueItemJson != null) {
          lexicalItemJson['progress'] = {
            'type': 'learning',
            'learning_stages': [
              {
                'type': 'suspended',
                'learning_event': 'added_to_learning_queue',
                'time': {
                  'ms': lexicalItemLearningQueueItemJson['added_time_ms'],
                },
                'repetition_number': 0,
              },
            ],
          };
        }

        if (lexicalItemBrainBoostListItemJson != null) {
          lexicalItemJson['progress'] = {
            'type': 'learning',
            'learning_stages': [
              {
                'type': 'suspended',
                'learning_event': 'marked_as_unknown',
                'time': {
                  'ms': lexicalItemBrainBoostListItemJson['added_time_ms'],
                },
                'repetition_number': 0,
              },
            ],
          };
        }
      } else {
        final lexicalItemProgressJson =
            Map.castFrom<dynamic, dynamic, String, dynamic>(lexicalItemProgressMap);
        final progressType = lexicalItemProgressJson['type'];

        if (progressType == 'previously_known') {
          lexicalItemJson['progress'] = {
            'type': 'previously_known',
            'time': {
              'ms': lexicalItemProgressJson['added_time_ms'],
            },
          };
        } else if (progressType == 'learning') {
          final int progress = lexicalItemProgressJson['progress'];

          const repeatIntervals = [
            Duration(hours: 6),
            Duration(hours: 20),
            Duration(hours: 64),
            Duration(hours: 164),
            Duration(hours: 332),
          ];

          final int? repeatTimeMs = lexicalItemProgressJson['repeat_time_ms'];

          int? lastBrainBoostEndTimeMs;

          if (repeatTimeMs != null) {
            lastBrainBoostEndTimeMs = repeatTimeMs - repeatIntervals[progress].inMilliseconds;
          }

          late final List<Map<String, dynamic>> learningStageJsons;

          final answerHistoryItemMaps =
              List.castFrom<dynamic, Map>(lexicalItemProgressJson['answer_history']);

          if (answerHistoryItemMaps.isEmpty) {
            learningStageJsons = [
              {
                'type': 'suspended',
                'learning_event': 'marked_as_unknown',
                'time': {
                  'ms': lexicalItemProgressJson['added_time_ms'],
                },
                'repetition_number': 0,
              },
              {
                'type': 'repeatable',
                'learning_event': 'marked_as_unknown',
                'time': {
                  'ms': lastBrainBoostEndTimeMs!,
                },
                'repetition_number': 0,
              },
            ];
          } else {
            learningStageJsons = [
              {
                'type': 'repeatable',
                'learning_event': 'marked_as_unknown',
                'time': {
                  'ms': lexicalItemProgressJson['added_time_ms'],
                },
                'repetition_number': 0,
              },
            ];

            var repetitionNumber = 0;

            String? previousLearningEvent;

            for (var i = 0; i < answerHistoryItemMaps.length; i++) {
              final answerHistoryItemJson =
                  Map.castFrom<dynamic, dynamic, String, dynamic>(answerHistoryItemMaps[i]);

              final String? answer = answerHistoryItemJson['answer'];

              late String learningEvent;

              if (answer == null) {
                learningEvent = 'marked_as_completely_learned';
              } else if (answer == 'dont_remember') {
                learningEvent = 'marked_as_unremembered';
              }
              if (answer == 'badly_remember') {
                learningEvent = 'marked_as_badly_remembered';
              }
              if (answer == 'remember') {
                learningEvent = 'marked_as_remembered';
              }

              if (learningEvent == 'marked_as_completely_learned') {
                repetitionNumber = 5;
              } else if (learningEvent == 'marked_as_unremembered') {
                repetitionNumber = max(0, repetitionNumber - 1);
              } else if (learningEvent == 'marked_as_badly_remembered') {
                if (previousLearningEvent != 'marked_as_remembered') {
                  repetitionNumber = max(0, repetitionNumber - 1);
                }
              } else if (learningEvent == 'marked_as_remembered') {
                repetitionNumber++;
              }

              final int answerTimeMs = answerHistoryItemJson['time_ms'];
              if (repetitionNumber == 5) {
                learningStageJsons.add({
                  'type': 'suspended',
                  'learning_event': learningEvent,
                  'time': {
                    'ms': answerTimeMs,
                  },
                  'repetition_number': repetitionNumber,
                });
              } else if (i == answerHistoryItemMaps.length - 1) {
                learningStageJsons.add({
                  'type': 'suspended',
                  'learning_event': learningEvent,
                  'time': {
                    'ms': answerTimeMs,
                  },
                  'repetition_number': repetitionNumber,
                });

                if (lexicalItemBrainBoostListItemJson == null && lastBrainBoostEndTimeMs != null) {
                  learningStageJsons.add({
                    'type': 'repeatable',
                    'learning_event': learningEvent,
                    'time': {
                      'ms': lastBrainBoostEndTimeMs,
                    },
                    'repetition_number': repetitionNumber,
                  });
                }
              } else {
                learningStageJsons.add({
                  'type': 'repeatable',
                  'learning_event': learningEvent,
                  'time': {
                    'ms': answerTimeMs,
                  },
                  'repetition_number': repetitionNumber,
                });
              }

              previousLearningEvent = learningEvent;
            }
          }

          lexicalItemJson['progress'] = {
            'type': 'learning',
            'learning_stages': learningStageJsons,
          };
        } else if (progressType == 'excluded') {
          lexicalItemJson['excluded'] = true;
        }
      }

      lexicalItemJson['excluded'] = lexicalItemJson['excluded'] ?? false;

      return lexicalItemJson;
    }).toList();

    //
    // collection list item migration
    //

    final collectionSettingsJson =
        Map.castFrom<dynamic, dynamic, String, dynamic>(ruBoxContent['collections_settings']);
    final collectionListItemMaps =
        List.castFrom<dynamic, Map>(ruBoxContent['collection_list_items']);

    void mergeCollectionJsonWithSettings({
      required Map<String, dynamic> collectionJson,
      required String collectionId,
      required Map<String, dynamic> collectionSettingsJson,
    }) {
      final Map thisCollectionSettings = collectionSettingsJson[collectionId];
      collectionJson['selected'] = thisCollectionSettings['selected'];
      collectionJson['high_priority'] = thisCollectionSettings['high_priority'];
      collectionJson['sorting'] = thisCollectionSettings['sorting'];
    }

    final collectionListItemJsons = collectionListItemMaps.map((collectionListItemMap) {
      final collectionListItemJson =
          Map.castFrom<dynamic, dynamic, String, dynamic>(collectionListItemMap);

      final collectionListItemType = collectionListItemJson['type'];

      if (collectionListItemType == 'default_collection') {
        final collectionJson = collectionListItemJson;

        collectionJson['type'] = 'inbuilt_collection';

        final collectionId = collectionJson['id'];

        mergeCollectionJsonWithSettings(
          collectionJson: collectionJson,
          collectionId: collectionId,
          collectionSettingsJson: collectionSettingsJson,
        );

        return collectionJson;
      }

      if (collectionListItemType == 'user_collection') {
        final collectionJson = collectionListItemJson;

        collectionJson['type'] = 'custom_collection';

        final collectionId = collectionJson['id'];

        mergeCollectionJsonWithSettings(
          collectionJson: collectionJson,
          collectionId: collectionId,
          collectionSettingsJson: collectionSettingsJson,
        );

        return collectionJson;
      }

      if (collectionListItemType == 'default_collection_group') {
        final collectionFolderJson = collectionListItemJson;

        collectionFolderJson['type'] = 'inbuilt_collection_folder';

        final collectionMaps = List.castFrom<dynamic, Map>(collectionFolderJson['collections']);

        collectionFolderJson['collections'] = collectionMaps.map((map) {
          final collectionJson = Map.castFrom<dynamic, dynamic, String, dynamic>(map);

          collectionJson['type'] = 'inbuilt_collection';

          final collectionId = collectionJson['id'];

          mergeCollectionJsonWithSettings(
            collectionJson: collectionJson,
            collectionId: collectionId,
            collectionSettingsJson: collectionSettingsJson,
          );

          return collectionJson;
        }).toList();

        return collectionFolderJson;
      }

      if (collectionListItemType == 'user_collection_group') {
        final collectionFolderJson = collectionListItemJson;

        collectionFolderJson['type'] = 'custom_collection_folder';

        final collectionMaps = List.castFrom<dynamic, Map>(collectionFolderJson['collections']);

        collectionFolderJson['collections'] = collectionMaps.map((map) {
          final collectionJson = Map.castFrom<dynamic, dynamic, String, dynamic>(map);

          collectionJson['type'] = 'custom_collection';

          final collectionId = collectionJson['id'];

          mergeCollectionJsonWithSettings(
            collectionJson: collectionJson,
            collectionId: collectionId,
            collectionSettingsJson: collectionSettingsJson,
          );

          return collectionJson;
        }).toList();

        return collectionFolderJson;
      }

      throw Exception();
    }).toList();

    ruBoxContent['lexical_items'] = lexicalItemJsons;
    ruBoxContent['collection_list_items'] = collectionListItemJsons;

    ruBoxContent.remove('brain_boost_list');
    ruBoxContent.remove('learning_queue');
    ruBoxContent.remove('added_to_brain_boost_unknown_lexical_item_times_ms');
    ruBoxContent.remove('alias_collections');
    ruBoxContent.remove('alias_settings');
    ruBoxContent.remove('collections_settings');
    ruBoxContent.remove('lexical_items_progress');
  });

  return updatedRuBoxContent;
}

BuiltMap _migrateSettingsBoxContentFromFirstVersionToSecondOne({
  required BuiltMap settingsBoxContent,
}) {
  final updatedSettingsBoxContent = settingsBoxContent.rebuild((settingsBoxContent) {
    settingsBoxContent['pronunciation_settings'] = settingsBoxContent.remove('tts_settings');

    final trainingSettings = settingsBoxContent.remove('training_settings') as Map;

    trainingSettings['exercise_shuffle_enabled'] =
        trainingSettings.remove('exercise_shuffling_enabled');

    trainingSettings['translation_selection_exercise_enabled'] =
        trainingSettings.remove('translation_selection_training_exercise_enabled');

    trainingSettings['audio_exercise_enabled'] =
        trainingSettings.remove('audio_training_exercise_enabled');

    trainingSettings['typing_exercise_enabled'] =
        trainingSettings.remove('typing_training_exercise_enabled');

    final learningAutoPronunciationEnabled =
        settingsBoxContent.remove('learning_auto_pronunciation_enabled') as bool;

    final learningSettings = <String, dynamic>{
      'training_settings': trainingSettings,
      'auto_pronunciation_enabled': learningAutoPronunciationEnabled,
    };

    settingsBoxContent['learning_settings'] = learningSettings;
  });

  return updatedSettingsBoxContent;
}

BuiltMap _migrateUserBoxContentFromFirstVersionToSecondOne({
  required BuiltMap userBoxContent,
}) {
  String parseTimeIso8601String({
    required Map<String, dynamic> timeJson,
  }) {
    final milliseconds = timeJson['ms'] as int;

    final time = DateTime.fromMillisecondsSinceEpoch(
      milliseconds,
      isUtc: true,
    );

    return time.toIso8601String();
  }

  final updatedUserBoxContent = userBoxContent.rebuild((userBoxContent) {
    // app review request times

    final appReviewRequestTimeMaps =
        List.castFrom<dynamic, Map>(userBoxContent['app_review_request_times']);

    final appReviewRequestTimeJsons = appReviewRequestTimeMaps.map((appReviewRequestTimeMap) {
      final appReviewRequestTimeJson =
          Map.castFrom<dynamic, dynamic, String, dynamic>(appReviewRequestTimeMap);

      final appReviewRequestTimeString = parseTimeIso8601String(
        timeJson: appReviewRequestTimeJson,
      );

      return appReviewRequestTimeString;
    }).toList();

    userBoxContent['app_review_request_times'] = appReviewRequestTimeJsons;

    // learning info

    final learningInfoJson =
        Map.castFrom<dynamic, dynamic, String, dynamic>(userBoxContent['learning_info']);

    final currentLearningIntervalStartTimeMap =
        learningInfoJson['current_learning_interval_start_time'] as Map?;

    if (currentLearningIntervalStartTimeMap != null) {
      final currentLearningIntervalStartTimeJson =
          Map.castFrom<dynamic, dynamic, String, dynamic>(currentLearningIntervalStartTimeMap);

      learningInfoJson['current_learning_interval_start_time'] = parseTimeIso8601String(
        timeJson: currentLearningIntervalStartTimeJson,
      );
    }

    final currentLearningIntervalLastKnownActivityTimeMap =
        learningInfoJson['current_learning_interval_last_known_activity_time'] as Map?;

    if (currentLearningIntervalLastKnownActivityTimeMap != null) {
      final currentLearningIntervalLastKnownActivityTimeJson =
          Map.castFrom<dynamic, dynamic, String, dynamic>(
              currentLearningIntervalLastKnownActivityTimeMap);

      learningInfoJson['current_learning_interval_last_known_activity_time'] =
          parseTimeIso8601String(
        timeJson: currentLearningIntervalLastKnownActivityTimeJson,
      );
    }

    final learningSessionMaps = List.castFrom<dynamic, Map>(learningInfoJson['learning_sessions']);

    final learningSessionJsons = learningSessionMaps.map((learningSessionMap) {
      final learningSessionJson =
          Map.castFrom<dynamic, dynamic, String, dynamic>(learningSessionMap);

      final learningIntervalMaps =
          List.castFrom<dynamic, Map>(learningSessionJson['learning_intervals']);

      final learningIntervalJsons = learningIntervalMaps.map((learningIntervalMap) {
        final learningIntervalJson =
            Map.castFrom<dynamic, dynamic, String, dynamic>(learningIntervalMap);

        final startTimeJson =
            Map.castFrom<dynamic, dynamic, String, dynamic>(learningIntervalJson['start_time']);

        learningIntervalJson['start_time'] = parseTimeIso8601String(
          timeJson: startTimeJson,
        );

        final endTimeJson =
            Map.castFrom<dynamic, dynamic, String, dynamic>(learningIntervalJson['end_time']);

        learningIntervalJson['end_time'] = parseTimeIso8601String(
          timeJson: endTimeJson,
        );

        return learningIntervalJson;
      }).toList();

      learningSessionJson['learning_intervals'] = learningIntervalJsons;

      return learningSessionJson;
    }).toList();

    learningInfoJson['learning_sessions'] = learningSessionJsons;

    userBoxContent['learning_info'] = learningInfoJson;
  });

  return updatedUserBoxContent;
}
